home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Programming / tek / doc / manuals / tasks2 < prev    next >
Encoding:
Text File  |  2001-05-21  |  4.8 KB  |  167 lines

  1.  
  2. TEKLIB MULTITASKING, WHY POLLING SUCKS
  3. ------------------------------------------------------------
  4.  
  5. tasks in a multithreaded application usually need to
  6. exchange data in one or another way.  try to imagine the
  7. following scenarios:
  8.  
  9. 1.  a subtask is launched with a clearly defined,
  10. time-consuming calculation.  all parameters are known upon
  11. startup.
  12.  
  13. 2.  a subtask is launched to act as a maintenance service in
  14. the background.  it checks certain data fields at regular
  15. time intervals, and sometimes performs some calculations
  16. accordingly.
  17.  
  18. 3.  a subtask is launched, performs some initializations,
  19. and then goes to sleep.  the main program (or another task)
  20. wakes it up and commissions jobs to the subtask whenever
  21. needed.
  22.  
  23. in reality, these cases are not so clearly separated from
  24. each other.  consider a fractal generator.  the parameters
  25. for the calculation are known upon startup:  all we need to
  26. do is to launch a task with a data packet containing the
  27. fractal's paramater range, number of iterations, pointer to
  28. a destination buffer, etc.
  29.  
  30. TEKlib offers you a very simple data sharing mechanism for
  31. that purpose.  a packet of userdata can be supplied upon a
  32. task's creation, and queried later from the task handle in
  33. the child context.
  34.  
  35. put all required data into a structure, and submit a pointer
  36. to it throughout the tag argument TTask_UserData:
  37.  
  38. struct fractaldata
  39. {
  40.     TFLOAT x1, y1, x2, y2;
  41.     TINT iterations;
  42.     TAPTR destbuffer;
  43.     TINT width, height;
  44. };
  45.  
  46. void main(void)
  47. {
  48.     ..
  49.     
  50.     TTAGITEM tasktags[2];
  51.     struct fractaldata userdata;
  52.  
  53.     userdata.x1 = -0.2;
  54.     userdata.y1 = -0.2;
  55.     userdata.x2 = 0.2;
  56.     userdata.y2 = 0.2;
  57.     userdata.iterations = 1024;
  58.     userdata.destbuffer = gfxbuffer;
  59.  
  60.     TInitTags(tasktags);
  61.     TAddTag(tasktags, TTask_UserData, &userdata);
  62.     
  63.     fractaltask = TCreateTask(basetask, fractalfunc, tasktags);
  64.     
  65.     ..
  66. }
  67.  
  68. TVOID fractalfunc(TAPTR task)
  69. {
  70.     struct fractaldata *userdata = TTaskGetData(task);
  71.  
  72.     ..
  73. }
  74.  
  75. first have a look at how the userdata argument is handled:
  76. for passing n tags to a function, you need to reserve a tag
  77. array with n+1 entries.  a tag is merely an ID/data pair
  78. each.  a tag array is initialized with TInitTags(),
  79. individual entries can then be added to the array with
  80. TAddTag().
  81.  
  82. now have a look at fractalfunc(), and see how the shared
  83. data packet is retrieved from the task handle.  this is a
  84. very raw and primitive example; no synchronization needs to
  85. take place here, and the same could normally be achieved
  86. with a few global variables.
  87.  
  88. but for heaven's sake, DO NOT USE GLOBAL VARIABLES for
  89. sharing data between tasks in TEKlib.  not only that your
  90. application may shortly look confusing and become overly
  91. complex; parts of it will be no longer reusable, and
  92. race-conditions start creeping into your design.  however.
  93. global variables for sharing data between tasks simply DO
  94. NOT WORK on all supported platforms, and you'd be
  95. sacrificing portability.  it's as easy as that.
  96.  
  97. ok, let's get back to the example.  how does the parent task
  98. know when the child task has finished?  how do we tell the
  99. parent task to draw a new line from the destination buffer
  100. to the screen?  there are many ways to achieve this; we
  101. start with the bad ones and come to the more elegant
  102. solutions later.
  103.  
  104. first, we might extend the userdata structure with some more
  105. fields:
  106.  
  107. struct fractaldata
  108. {
  109.     ..
  110.     
  111.     TINT line_rendered;
  112.     TBOOL finished;
  113. };
  114.  
  115. the subtask would have to update the field line_rendered
  116. with the current line, and set the boolean to TTRUE once it
  117. has finished.  the parent could then check the userdata
  118. structure from time to time, and update the display
  119. accordingly:
  120.  
  121. void main(void)
  122. {
  123.     ..
  124.     userdata.finished = TFALSE;    
  125.     userdata.line_rendered = 0;
  126.     ..
  127.     fractaltask = TCreateTask(basetask, fractalfunc, tasktags);
  128.     if (fractaltask)
  129.     {
  130.         TINT lastline = 0;
  131.         
  132.         while (!userdata.finished)
  133.         {
  134.             if (userdata.line_rendered != lastline)
  135.             {
  136.                 lastline = userdata.line_rendered;
  137.                 drawline(screen, gfxbuffer, lastline - 1);
  138.             }
  139.  
  140.             /* maybe do something else here */
  141.         }
  142.  
  143.         TDestroy(fractaltask);
  144.     }
  145.     ..
  146. }
  147.  
  148. that would work, undoubtedly.  but this example is awful;
  149. the loop will consume all the CPU time it can get, leaving
  150. only 50% of the available resources to the fractal task,
  151. thus making the application behave very slow and unfriendly.
  152.  
  153. to get away from that, you should insert a call to
  154. TTimeDelayF() to the loop.  that would make the program,
  155. well, acceptable at best.  this is called polling.  its
  156. disadvantage should be obvious:  the less time you waste for
  157. polling, the larger the latency inflicted to your program!
  158.  
  159. you may think that you've got enough clock cycles in your
  160. brand new Dual Athlium 5,7ghz computer to waste for polling
  161. in intervals of microseconds...  but try to imagine HOW MANY
  162. threads of execution might be handling their execution flow
  163. like that, leading to gazillions of useless context
  164. switches, and in the end, to accelerated increase of entropy
  165. in our local universe.
  166.  
  167.